<?php

namespace app\usedb\controller;

use app\BaseController;
use app\usedb\model\Szx;
use app\usedb\model\Xsb;
use app\validate\Student;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;

class Chain extends BaseController
{
    public function chain_opt()
    {
        // 链式操作

        // 查全部操作
        // field('*')   等效于   SELECT * FROM user
        $list = Db::name('xsb')
            ->field('*')
            ->select();
        dump($list);
        // field(true)   等效于    SELECT `xh`,`xm`,`headimg`,`sex`,`age`,`szx`,`del` FROM `zx_xsb`

        // 直接取出字段取值，速度比*快，适用于对性能要求比较高的系统
        $list2 = Db::name('xsb')
            ->field(true)
            ->select();
        dump($list2);

        // 字段排除取出 withoutField('需要排除的字段名')
        $list3 = Db::name('xsb')
            ->withoutField('xm')
            ->select();
        dump($list3);

        // 限制显示结果数量 limit(起始位置, 步长)
        $list4 = Db::name('xsb')
            ->limit(5, 5)
            ->select();
        dump($list4);

        // 分页显示 page(页数, 每页显示数量)
        $list5 = Db::name('xsb')
            ->page(3, 5)
            ->select();
        dump($list5);

        // 排序输出(默认升序) order('字段名', '排序规则')
        $list6 = Db::name('xsb')
            ->order('age', 'desc')
            ->select();
        dump($list6);

        // 分组查询
        // 一旦使用了分组
        // 查询时 只能查询分组字段以及聚合查询
        $list7 = Db::name('xsb')
            ->field('szx, count(*), avg(age), sum(age), max(age), min(age)')
            ->group('szx')
            ->having('avg(age)>=25')    // 过滤分组having
            ->select();
        dump($list7);

        // 去除重复数据 distinct()
        $list8 = Db::name('xsb')
            ->field('szx')
            ->distinct(true)        // 默认为true
            ->select();
        dump($list8);

        // 缓存 cache('缓存命名') 将从数据库提取到的数据存储到缓存里，下次使用直接提取出来，节省数据库资源
        $list8 = Db::name('xsb')
            ->cache('lzc', 60)  // 第一个参数为缓存名字 第二个参数为缓存的有效时间
            ->field(true)
            ->select();
        dump($list8);

        // 聚合查询  统计数量count() 取最大值max() 取最小值min() 求平均avg() 求和sum()
        $list9 = Db::name('xsb')
            ->count();
        dump($list9);
    }

    public function m_use()
    {
        // 使用模型查询数据
        // Db类使用select方法得到的结果集是数组
        // 模型类使用select方法得到的结果集是结果集对象
        $list1 = Xsb::select();
        dump($list1);
        $list2 = Db::name('xsb')->select();
        dump($list2);
        $list1->each(function ($value) {
            if ($value['sex'] == '男')
                $value['sex'] = '高富帅';
            else
                $value['sex'] = '白富美';
            // 模型类 $value是对象，修改的是对象，整个对象变了则不需要返回值也能直接从对象读取到

            // 对象不能像数组一样按键添值,只能先将收集到的数据暂存到临时数组中
            $tmp[] = $value['xm'];
            // 收集完成后，将临时数组存储打开=带对象的某个属性中
            $value->son = $tmp;
        });
        dump($list1);
        $list2->each(function ($value) {
            if ($value['sex'] == '男')
                $value['sex'] = '高富帅';
            else
                $value['sex'] = '白富美';

            // 新增一个名为name数组，该数组键为'xm'
            $value['name'][] = $value['xm'];

            // Db类 $value是每一个结果集，修改的是数组，要把数组的返回值返回出来才能看到
            return $value; // 需要return返回数据，否则只显示null
        });
        dump($list2);
    }

    public function m_use2()
    {
//        // 接收请求
//        $get = $this->request->param();
//        dump($get);
//        // 导入自定义模型类Xsb，执行查询
//        $list = Xsb::m_select($get);
//
//        $list2 = Db::name('szx')
//            ->select();
//        dump($list, $list2);
//        dump(Session::all());
//
//        View::assign('list', $list);
//        View::assign('list2', $list2);
//        return View::fetch();

//        // 通过判断session中的用户信息是否存在来判断用户是否已登录
//        if (!Session::has('user')){
//            $this->error('请登录再试', url('login/login'), array(), 3);
//        }

        // 接收请求
        $get = $this->request->param();
        dump($get);
        // 导入自定义模型类Xsb，执行查询
        $list = Xsb::m_select($get);

        $list2 = Db::name('szx')
            ->select();
        dump($list, $list2);
        dump(Session::all());

        View::assign('list', $list);
        View::assign('list2', $list2);
        return View::fetch();
    }

    public function m_query()
    {
        // 模型查询
        // 模型类::find() 获取单个数据
        $one = Xsb::find(9512101);
        dump($one);  // 得到的是模型结果集

        // 无论条件符合多少条，只会显示第一条
        $one = Xsb::where('sex', '=', '男')->find();
        dump($one);

        // 模型类::select() 获取多个数据
        $mult = Xsb::select([9512101, 9512103]);
        dump($mult);

        $mult = Xsb::where('sex', '=', '男')->select();
        dump($mult);
    }

    public function m_delete()
    {
        // 模型删除  先查询再删除
        // 使用模型结果集中的delete方法删除
//        $user = Xsb::find(9531177)
//            ->delete();

        // 模型::destory() 静态方法删除
//        $user = Xsb::destroy(9531176);
        // 同时删除多条记录
//        $user = Xsb::destroy([9531175, 9531174]);
        // 条件删除
//        $user = Xsb::destroy(function ($query){
//           $query->where('age', '>=', '30');
//        });

//        // 增加html返回学号进行软删除功能
//        $xh = $this->request->param('xh');  // 接收删除操作传回来的学号参数
        // 直接接收前端传回来的学号和条件查询参数
        $all = $this->request->param();
        $rt = Xsb::del($all['xh']);  // 传入学号到del自定义删除功能
//        dump($rt);
        // 按删除成功和失败跳转渲染页面
        if ($rt['error'] == 0) {
            // 删除成功
            unset($all['xh']); // $all中出了搜索条件外还有学号，需要unset()销毁学号才能传入下面的跳转携带参数里
            // success(提示信息, 跳转url地址, 携带参数, 等待时间)
            $this->success($rt['msg'], url('m_use2', $all), array(), 5);
        } else {
            // 删除失败 返回至列表页
            $this->error($rt['msg']);
        }
    }

    public function m_add()
    {
        // 使用模型添加
        // 新增数据的最佳实践原则：使用create方法新增数据，使用saveAll批量新增数据。

        $xsb = new Xsb();
        // 1.使用 save() 方法动态添加
//        $xsb->xm='老铁';
//        $xsb->sex='男';
//        $xsb->age=18;
//        $xsb->save();

        // 1.2使用数组添加
//        $arr = array(
//            'xm'=>'老六',
//            'sex'=>'女',
//            'age'=>23
//        );
//        $xsb->save($arr);
        // 如果通过外部提交赋值给模型，并且希望指定的某些字段写入，可以使用allowField
//        $xsb->allowField(['xm', 'sex'])->save($arr);

        // 1.3批量使用模型添加数据 insertAll() （不支持静态方法）
        $arr = [
            [
                'xm' => '田七',
                'sex' => '女',
                'age' => '18'
            ],
            [
                'xm' => '田七2',
                'sex' => '女',
                'age' => '18'
            ],
            [
                'xm' => '田七3',
                'sex' => '女',
                'age' => '18'
            ]
        ];
        $rt = $xsb->insertAll($arr);
        dump($rt);  // 发现返回的是添加成功数据的条数 3

        // 2.使用 模型类::create() 静态方法创建并写入
//        $arr = array(
//            'xm'=>'李四',
//            'sex'=>'女',
//            'age'=>'18'
//        );
//        $user = Xsb::create($arr);
//        dump($user);
    }

    public function validate_use()
    {
        // 使用验证器验证信息是否合法
        $arr = [
            'xm' => '老八',
            'sex' => '女',
            'age' => 80
        ];

//        // 1.实例化类验证方式
//        $stu = new Student();
//        // 不开启批量验证返回的报错信息是字符串
////        $rt = $stu->check($arr);
//        // 加入batch(true)批量验证可以返回多个验证是否通过的信息数组
//        $rt = $stu->batch(true)->check($arr);
//        // 验证通过时返回true，不通过返回false
//        dump($rt);
//        if (!$rt) { // 如果为false 则返回报错信息
//            dump($stu->getError());
//        }

        // 2.助手函数验证方式
        // validate(验证类名::class)
        // 该方法验证通过没有信息，失败时会抛出异常，需要try-catch捕获
        try {
            validate(Student::class)
                ->scene('只验证姓名和性别')     // 使用场景模式
                ->batch(true)
                ->check($arr);
        } catch (ValidateException $e) {    // ValidateException只会捕获验证异常信息，过滤掉其他报错信息
            dump($e->getError());
        } catch (\Exception $e) {
            dump('系统错误!');  // 其他异常捕获提示系统错误
        }
    }

    public function form_token()
    {
        if ($this->request->isPost()) {
            // 处理请求之前 先对token进行合法性的验证
            // 1.控制器验证 返回布尔值 token合法返回true 不合法返回false
//            $rt = $this->request->checkToken('__token__'); // 参数为表单令牌的名字
//            dump($rt);
//            // 验证成功后才执行下面的代码
//            if ($rt) {
//                dump('通过验证');
//                $get = $this->request->param();
//                dump($get);
//            } else {
//                dump('验证失败');
//            }

            // 2.验证器验证
            $get = $this->request->param();
            dump($get);
            try {
                validate(Student::class)->batch(true)->check($get);
            } catch (ValidateException $e) {
                dump($e->getError());
            }

            return View::fetch();
        } else {    // 展示表单
            return View::fetch();
        }
    }

    public function add_token()
    {
        if ($this->request->isPost()) {  // 提交表单请求时
            $param = $this->request->param();
//            $file = $this->request->file(); // 单独处理文件二进制数据
//            halt($param, $file);

            // 此处进入模型层处理数据（1.验证数据合法性 2.写入保存到数据库）
//            $rt = Xsb::add($param, $file);
            $rt = Xsb::add($param);

            // 页面跳转
            if ($rt['error'] == 0)   // 如果验证成功,跳转至m_use2搜索页面
            {
                $this->success($rt['msg'], url('m_use2'), array(), 10);
            } else {    // 如果验证失败，跳转回添加页面
                $this->error($rt['msg'], url('add_token'), array(), 10);
            }
        } else {    // 没有提交表单请求时
            // 查询全部的系
            View::assign('szx_list', Szx::select());
            return View::fetch();
        }
    }

    public function m_update()
    {
        // 模型修改
        // 先查找再更新

        // save() 方法更新（这种方式是最佳的更新方式）
        // 修改单个字段
//        $info = Xsb::find(9521103);
//        $info->xm = '李大钊';
//        $info->age = '22';
//        $info->save();
//        dump($info);

        // 使用数组修改修改
//        $arr = [
//            'xm' => '李大钊',
//            'age' => '23'
//        ];
//        $info->save($arr);
        // 只改姓名
//        $info->allowField(['xm'])->save($arr);

        // update() 模型静态方法更新
        // 方式1：2个参数 update（要修改的数组, 条件数组）
//        $arr = [
//            'xm' => '李大钊',
//            'age' => '23'
//        ];
//        Xsb::update($arr, ['xm' => '李小龙']);

        // 方式2：1个参数 update(要修改的数组)   数组中必须要有主键
        $arr = [
            'xh' => '9521103',  // 主键
            'xm' => '李小龙',
            'age' => '24',
            'lzc' => '隐藏数据库里真正的名字',
        ];
        Xsb::update($arr);
    }
    public function edit_token()
    {
        if ($this->request->isPost())
        {   // 发送修改表单请求时
            // 接收请求参数
            $post = $this->request->post(); // 接收提交修改数据表单post请求携带的参数
            $get = $this->request->get();   // 接收选择搜索页面的get请求携带的参数+主键
//            $file = $this->request->file();  // 单独处理文件二进制数据
            dump($post, $get['xh']);

            // 传参到模型类进行修改
            $rt = Xsb::edit($post, $get['xh']);
            dump($rt);

            // 页面跳转
            if ($rt['error'] == 0)   // 如果验证成功,跳转至m_use2搜索页面
            {
                unset($get['xh']);
                $this->success($rt['msg'], url('m_use2', $get), array(), 10);
            } else {    // 如果验证失败，跳转回添加页面
                $this->error($rt['msg'], url('edit_token', $get), array(), 10);
            }
        } else {    // 没有表单请求时
            try {   // 没有请求参数请求时提前报错
                $all = $this->request->param();    // 得到的是学号数组
                // 查询该学生信息(单条)
                $one = Xsb::find($all['xh']);   // 得到的是按学号查询的结果集
                View::assign('list', $one);
                 // 查询全部的系
                View::assign('szx_list', Szx::select());
                return View::fetch();
            } catch (\Exception $e) {
                $this->error('error：404,非法请求');
            }
        }
    }
    public function ss()
    {
        // 使用session
        // 1.解开app/middleware.php中的session中间件

        // 2.使用think\facade\Session类 静态方法来使用session
        // (注意：使用完session后不能使用exit/die等停止程序操作，否则会导致session数据写入失败)
        Session::set('name', 'lzc1');
        $session_name = ['id'=>1,'name'=>'admin','email' => 'admin@qq.com'];
        Session::set('arr', $session_name);

        // 每一个客户端（浏览器） 访问服务器时，都会产生一个session
        // session是在访问开始时产生，在关闭浏览器时结束
        // 同一域名下所有的文件均在同一session下，并且数据共享
        // 当用户不操作页面时，session会在指定时间内config/session.php 配置 expire

    }
    public function read_ss()
    {
        // 读取session 存储位置在runtime/session里
        dump(Session::get('name'));
        // 读取全部
        dump(Session::all());
        // 判断是否存在
        dump(Session::has('arr'));
        // 删除
        Session::delete('name');
        // 清空
        Session::clear();
    }
}